#include "LabelDistributionSqlWriter.h"
#include <string>
#include <assert.h>
#include <sstream>

#define users users
#define items items
#define DROPTABLE(x) "DROP TABLE IF EXISTS " #x "\0"
#define CREATETABLE(x) "CREATE TABLE " #x "(node NCHAR(255), label NCHAR(255), weight DOUBLE )\0"
#define INSERT(x) "INSERT INTO " #x "(node, label, weight) VALUES ( @k, @v, @w )"
#define INSERT_NEW(x) "INSERT INTO " #x "(node, label, weight) SELECT "

void LabelDistributionSqlWriter::ExecSql(char* sql)
{
	sqlite3_stmt *stmt;
	int iErr;
	if ((iErr = sqlite3_prepare_v2(m_sql, sql, -1, &stmt, NULL)) != SQLITE_OK)
		abort();
	if (sqlite3_step(stmt) != SQLITE_DONE)
		abort();
	sqlite3_finalize(stmt);
}

LabelDistributionSqlWriter::LabelDistributionSqlWriter(std::string &sOutputFileName)
{
	if(sqlite3_open(sOutputFileName.c_str(), &m_sql) != SQLITE_OK)
	{
		sqlite3_close(m_sql);
		abort();
	}
	ExecSql(DROPTABLE(users));
	ExecSql(DROPTABLE(items));
	ExecSql(CREATETABLE(users));
	ExecSql(CREATETABLE(items));
}

LabelDistributionSqlWriter::~LabelDistributionSqlWriter()
{
	sqlite3_close(m_sql);
}

int LabelDistributionSqlWriter::Write(Node *key, ListLabel *val)
{
	sqlite3_stmt *stmtInsert;
	int iRet;
	std::stringstream streamInsertCmd;

	switch (key->Type)
	{
	case NodeTypeItem:
		streamInsertCmd << INSERT_NEW(items);
		break;
	case NodeTypeUser:
		streamInsertCmd << INSERT_NEW(users);
		break;
	default:
		abort();
	}
	
	for (ListLabel::iterator itLabel(val->begin()), itLabelEnd(val->end());
		itLabel != itLabelEnd; itLabel++)
	{
		streamInsertCmd << "\"" << key->Id.c_str() << "\", ";
		streamInsertCmd << "\"" << (*itLabel)->data.c_str() << "\", ";
		streamInsertCmd << (*itLabel)->weight;

		if ((itLabel + 1) != itLabelEnd)
		{
			streamInsertCmd << " UNION SELECT ";
		}
	}

	iRet = sqlite3_prepare_v2(m_sql, streamInsertCmd.str().c_str(), -1, &stmtInsert, NULL);
	assert(iRet == SQLITE_OK);
	do 
	{
		iRet = sqlite3_step(stmtInsert);
	} while (iRet == SQLITE_ROW);
	assert(iRet == SQLITE_DONE);
	sqlite3_finalize(stmtInsert);

	return 1;
}

